#include "bsp_sys.h"
#include "bsp_usart.h"
#include "bsp_delay.h"

#define USART1_REC_LEN	512
#define USART1_SEN_LEN	512
static u8 USART1_RX_BUF[USART1_REC_LEN];  
static u8 USART1_TX_BUF[USART1_SEN_LEN];
static STRUCT_DATA_BUF RxBuf = {
	USART1_RX_BUF,
	USART1_REC_LEN
};
static STRUCT_DATA_BUF TxBuf = {
	USART1_TX_BUF,
	USART1_SEN_LEN
};

static STRUCT_FIFO UartTxFIFO;//USART transmitting
static STRUCT_FIFO UartRxFIFO;//USART receiving


void Uart_Init(STRUCT_DATA_BUF* pRxBuf, STRUCT_DATA_BUF* pTxBuf)
{
    //GPIO端口设置
    GPIO_InitTypeDef GPIO_InitStructure;
    USART_InitTypeDef USART_InitStructure;
	NVIC_InitTypeDef NVIC_InitStructure;
	NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2); //设置NVIC中断分组2:2位抢占优先级，2位响应优先级
#if USART1_CONFIG_ENABLED      /* 串口配置使能判断，串口1 TX = PA9   RX = PA10 */
    /* 第1步：打开GPIO和USART部件的时钟 */
    RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA | RCC_APB2Periph_AFIO, ENABLE);
    RCC_APB2PeriphClockCmd(RCC_APB2Periph_USART1, ENABLE);
    /* 第2步：将USART Tx的GPIO配置为推挽输出模式 */
    GPIO_InitStructure.GPIO_Pin = GPIO_Pin_9; //PA.9
    GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
    GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP; //复用推挽输出
    GPIO_Init(GPIOA, &GPIO_InitStructure);
    /* 第3步：将USART Rx的GPIO配置为浮空输入模式 */
    GPIO_InitStructure.GPIO_Pin = GPIO_Pin_10;
    GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING;//浮空输入
    GPIO_Init(GPIOA, &GPIO_InitStructure);
	//NVIC配置
	NVIC_InitStructure.NVIC_IRQChannel = USART1_IRQn;
    NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0 ; 	//抢占优先级3
    NVIC_InitStructure.NVIC_IRQChannelSubPriority = 1;      	//子优先级3
    NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;         	//IRQ通道使能
    NVIC_Init(&NVIC_InitStructure); //根据指定的参数初始化VIC寄存器
    // 第4步：USART 初始化设置
    USART_InitStructure.USART_BaudRate = BOUND9600;//头文件宏定义，方便移植;
    USART_InitStructure.USART_WordLength = USART_WordLength_8b;//字长为8位数据格式
    USART_InitStructure.USART_StopBits = USART_StopBits_1;//一个停止位
    USART_InitStructure.USART_Parity = USART_Parity_No;//无奇偶校验位
    USART_InitStructure.USART_HardwareFlowControl = USART_HardwareFlowControl_None;//无硬件数据流控制
    USART_InitStructure.USART_Mode = USART_Mode_Rx | USART_Mode_Tx; //收发模式
    USART_Init(USART1, &USART_InitStructure); //初始化串口
    USART_ITConfig(USART1, USART_IT_RXNE, ENABLE);//开启中断
    USART_Cmd(USART1, ENABLE);                    //使能串口
    /* CPU的小缺陷：串口配置好，如果直接Send，则第1个字节发送不出去
    如下语句解决第1个字节无法正确发送出去的问题 */
    USART_ClearFlag(USART1, USART_FLAG_TC);     /* 清除发送完成标志 */
	
	if(pRxBuf == NULL || pTxBuf == NULL){
		NVIC_SystemReset();
	}
	else{
		UartRxFIFO.pFFData = pRxBuf->pBuf;		// to initialize receive FIFO
		UartRxFIFO.FFDepth = pRxBuf->size;
		UartRxFIFO.FFValidSize = 0;
		UartRxFIFO.FFInOffset = 0;
		UartRxFIFO.FFOutOffset = 0;

		UartTxFIFO.pFFData = pTxBuf->pBuf;		// to initialize transmit FIFO
		UartTxFIFO.FFDepth = pTxBuf->size;
		UartTxFIFO.FFValidSize = 0;
		UartTxFIFO.FFInOffset = 0;
		UartTxFIFO.FFOutOffset = 0;
	}
	
#endif
#if USART2_CONFIG_ENABLED                  /*串口配置使能判断， 串口2 TX = PA2， RX = PA3  */
    //使能GPIOA,复用功能以及USART2时钟
    RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA | RCC_APB2Periph_AFIO, ENABLE);
    RCC_APB1PeriphClockCmd(RCC_APB1Periph_USART2, ENABLE);
    //USART2_TX   PA.2
    GPIO_InitStructure.GPIO_Pin = GPIO_Pin_2; //PA.2
    GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
    GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP; //复用推挽输出
    GPIO_Init(GPIOA, &GPIO_InitStructure);
    //USART2_RX   PA.3
    GPIO_InitStructure.GPIO_Pin = GPIO_Pin_3;
    GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING;//浮空输入
    GPIO_Init(GPIOA, &GPIO_InitStructure);
	//NVIC配置
	NVIC_InitStructure.NVIC_IRQChannel = USART2_IRQn;
    NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0 ; 	//抢占优先级3
    NVIC_InitStructure.NVIC_IRQChannelSubPriority = 2;      	//子优先级3
    NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;         	//IRQ通道使能
    NVIC_Init(&NVIC_InitStructure); //根据指定的参数初始化VIC寄存器	
    //USART 初始化设置
    USART_InitStructure.USART_BaudRate = BOUND9600;       //见宏定义;
    USART_InitStructure.USART_WordLength = USART_WordLength_8b;//字长为8位数据格式
    USART_InitStructure.USART_StopBits = USART_StopBits_1;//一个停止位
    USART_InitStructure.USART_Parity = USART_Parity_No;//无奇偶校验位
    USART_InitStructure.USART_HardwareFlowControl = USART_HardwareFlowControl_None;//无硬件数据流控制
    USART_InitStructure.USART_Mode = USART_Mode_Rx | USART_Mode_Tx; //收发模式
    USART_Init(USART2, &USART_InitStructure); //初始化串口
    USART_ITConfig(USART2, USART_IT_RXNE, ENABLE);//开启中断
    USART_Cmd(USART2, ENABLE);
    USART_ClearFlag(USART2, USART_FLAG_TC);     /* 清除发送完成标志 */
#endif
#if USART3_CONFIG_ENABLED                  /*串口配置使能判断， 串口3 TX = PB10， RX = PB11  */
    //使能GPIOB,复用功能以及USART3时钟
    RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB | RCC_APB2Periph_AFIO, ENABLE);
    RCC_APB1PeriphClockCmd(RCC_APB1Periph_USART3, ENABLE);
    //USART3_TX   PB.10
    GPIO_InitStructure.GPIO_Pin = GPIO_Pin_10; //PB.10
    GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
    GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP; //复用推挽输出
    GPIO_Init(GPIOB, &GPIO_InitStructure);
    //USART3_RX   PB.11
    GPIO_InitStructure.GPIO_Pin = GPIO_Pin_11;
    GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING;//浮空输入
    GPIO_Init(GPIOB, &GPIO_InitStructure);
	//NVIC配置
	NVIC_InitStructure.NVIC_IRQChannel = USART3_IRQn;
    NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0 ; 	//抢占优先级3
    NVIC_InitStructure.NVIC_IRQChannelSubPriority = 3;      	//子优先级3
    NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;         	//IRQ通道使能
    NVIC_Init(&NVIC_InitStructure); //根据指定的参数初始化VIC寄存器
    //USART 初始化设置
    USART_InitStructure.USART_BaudRate = BOUND9600;       //见宏定义;
    USART_InitStructure.USART_WordLength = USART_WordLength_8b; //字长为8位数据格式
    USART_InitStructure.USART_StopBits = USART_StopBits_1;//一个停止位
    USART_InitStructure.USART_Parity = USART_Parity_No;//无奇偶校验位
    USART_InitStructure.USART_HardwareFlowControl = USART_HardwareFlowControl_None;//无硬件数据流控制
    USART_InitStructure.USART_Mode = USART_Mode_Rx | USART_Mode_Tx; //收发模式
    USART_Init(USART3, &USART_InitStructure); //初始化串口
    USART_ITConfig(USART3, USART_IT_RXNE, ENABLE);//开启中断
    USART_Cmd(USART3, ENABLE);
    USART_ClearFlag(USART3, USART_FLAG_TC);     /* 清除发送完成标志 */
#endif 

}

void USART_Config(void)
{
	Uart_Init(&RxBuf, &TxBuf);
}


#if USART1_CONFIG_ENABLED 

void USART1_IRQHandler(void)
{
    if(USART_GetITStatus(USART1, USART_IT_RXNE) != RESET)
    {
    	if(UartRxFIFO.FFValidSize < UartRxFIFO.FFDepth){
			UartRxFIFO.pFFData[UartRxFIFO.FFInOffset++] = USART_ReceiveData(USART1);
			if(UartRxFIFO.FFInOffset == UartRxFIFO.FFDepth)	
				UartRxFIFO.FFInOffset = 0;
			UartRxFIFO.FFValidSize++;
		}
        
        USART_ClearITPendingBit(USART1, USART_IT_RXNE); //clear flag
    }

    if(USART_GetFlagStatus(USART1, USART_FLAG_ORE) == SET) //overflow
    {
        USART_ReceiveData(USART1);    // delete data
        USART_ClearFlag(USART1, USART_FLAG_ORE);
    }
}

u16 USART1_GetRxFFValidSize(void)
{
	return UartRxFIFO.FFValidSize;
}

u8 USART1_RecBuf(u8* pBuf, u16 len)
{
	if(UartRxFIFO.FFValidSize < len || len <= 0 || NULL == pBuf)
		return ERROR;
    
	while(len --){
		*pBuf++ = UartRxFIFO.pFFData[UartRxFIFO.FFOutOffset++];
		if(UartRxFIFO.FFOutOffset == UartRxFIFO.FFDepth)
			UartRxFIFO.FFOutOffset = 0;
		NVIC_DisableIRQ(USART1_IRQn);
		UartRxFIFO.FFValidSize --;
		NVIC_EnableIRQ(USART1_IRQn);
	}
	return SUCCESS;
}

u16 USART1_GetRxTotleDataLen(void)
{
    u16 retLen  = 0;
    do{
        retLen = USART1_GetRxFFValidSize();
        delay_ms(1);
    }while(retLen != USART1_GetRxFFValidSize());
    
    return retLen;
}

#endif



void USART_SendByte(USART_TypeDef* USARTx, u8 byte)
{
    /* 发送一个字节数据到USART */
    USART_SendData(USARTx, byte);

    /* 等待发送数据寄存器为空 */
    while(USART_GetFlagStatus(USARTx, USART_FLAG_TXE) == RESET);
}

void USART_SendBuf(USART_TypeDef* USARTx, u8 *str, u16 len)
{

   	while(len --)
    {
        USART_SendByte(USARTx, *str++);
    }
}





//如果使用ucos,则包括下面的头文件即可.
#if SYSTEM_SUPPORT_OS
#include "includes.h"                   //ucos 使用     
#endif

#if 1
#pragma import(__use_no_semihosting)
//标准库需要的支持函数
struct __FILE
{
    int handle;

};

FILE __stdout;
//定义_sys_exit()以避免使用半主机模式
void _sys_exit(int x)
{
    x = x;
}
//重定义fputc函数
int fputc(int ch, FILE *f)
{
    while((USART1->SR & 0X40) == 0); //循环发送,直到发送完毕

    USART1->DR = (u8) ch;
    return ch;
}
#endif



